switch client side encryption to use sha256 hash algorithm
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Wed, 22 Jan 2025 09:51:13 +0000 (10:51 +0100)
committerMatthieu Gallien <matthieu.gallien@nextcloud.com>
Thu, 23 Jan 2025 09:47:16 +0000 (10:47 +0100)
Close #5989

only support sha1 for depreceted read-only usage

use sha256 for new encrypted write operations

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/clientsideencryption.cpp

index f5ac68583a0d058b705439c1e2340bea828768a4..d797991ad1cacadb380bf6cbdbcb58d2da27eb06 100644 (file)
@@ -237,7 +237,32 @@ QByteArray deprecatedGeneratePassword(const QString& wordlist, const QByteArray&
                                        (const unsigned char *)salt.constData(),// const unsigned char *salt,
                                        salt.size(),                            // int saltlen,
                                        iterationCount,                         // int iterations,
-                                       EVP_sha1(),                             // digest algorithm
+                                       EVP_sha1(),                             // deprecated digest algorithm
+                                       keyLength,                              // int keylen,
+                                       unsignedData(secretKey));               // unsigned char *out
+
+    if (ret != 1) {
+        qCWarning(lcCse()) << "Failed to generate encryption key";
+        // Error out?
+    }
+
+    return secretKey;
+}
+
+QByteArray deprecatedSha1GeneratePassword(const QString& wordlist, const QByteArray& salt)
+{
+    const auto iterationCount = 600000;
+    const auto keyStrength = 256;
+    const auto keyLength = keyStrength / 8;
+
+    QByteArray secretKey(keyLength, '\0');
+
+    const auto ret = PKCS5_PBKDF2_HMAC(wordlist.toLocal8Bit().constData(),     // const char *password,
+                                       wordlist.size(),                        // int password length,
+                                       (const unsigned char *)salt.constData(),// const unsigned char *salt,
+                                       salt.size(),                            // int saltlen,
+                                       iterationCount,                         // int iterations,
+                                       EVP_sha1(),                             // deprecated digest algorithm
                                        keyLength,                              // int keylen,
                                        unsignedData(secretKey));               // unsigned char *out
 
@@ -262,7 +287,7 @@ QByteArray generatePassword(const QString& wordlist, const QByteArray& salt)
                                        (const unsigned char *)salt.constData(),// const unsigned char *salt,
                                        salt.size(),                            // int saltlen,
                                        iterationCount,                         // int iterations,
-                                       EVP_sha1(),                             // digest algorithm
+                                       EVP_sha256(),                           // digest algorithm
                                        keyLength,                              // int keylen,
                                        unsignedData(secretKey));               // unsigned char *out
 
@@ -1419,7 +1444,7 @@ std::pair<QByteArray, PKey> ClientSideEncryption::generateCSR(const AccountPtr &
         return {result, std::move(keyPair)};
     }
 
-    ret = X509_REQ_sign(x509_req, privateKey, EVP_sha1());    // return x509_req->signature->length
+    ret = X509_REQ_sign(x509_req, privateKey, EVP_sha256());    // return x509_req->signature->length
     if (ret <= 0){
         qCWarning(lcCse()) << "Error signing the csr with the private key";
         return {result, std::move(keyPair)};
@@ -1661,13 +1686,19 @@ void ClientSideEncryption::decryptPrivateKey(const AccountPtr &account, const QB
             const auto salt = EncryptionHelper::extractPrivateKeySalt(key);
 
             const auto deprecatedPassword = EncryptionHelper::deprecatedGeneratePassword(mnemonic, salt);
+            const auto deprecatedSha1Password = EncryptionHelper::deprecatedSha1GeneratePassword(mnemonic, salt);
             const auto password = EncryptionHelper::generatePassword(mnemonic, salt);
 
             const auto privateKey = EncryptionHelper::decryptPrivateKey(password, key);
             if (!privateKey.isEmpty()) {
                 _privateKey = privateKey;
             } else {
-                _privateKey = EncryptionHelper::decryptPrivateKey(deprecatedPassword, key);
+                const auto deprecatedSha1PrivateKey = EncryptionHelper::decryptPrivateKey(deprecatedSha1Password, key);
+                if (!privateKey.isEmpty()) {
+                    _privateKey = deprecatedSha1PrivateKey;
+                } else {
+                    _privateKey = EncryptionHelper::decryptPrivateKey(deprecatedPassword, key);
+                }
             }
 
             if (!_privateKey.isNull() && checkPublicKeyValidity(account)) {